package editorsvg.propiedades;

import editorsvg.editor.comandos.GestorComandos;
import java.awt.Color;
import java.awt.Font;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

/**
 * Representa un grupo de propiedades.
 *
 * @author Jorge Berjano
 */
public class GrupoPropiedades implements Cloneable {

    private String titulo;
    private ArrayList<Propiedad> listaPropiedades;
    private Hashtable<String, Propiedad> diccionario;
    private Hashtable<String, Propiedad> diccionarioAlias;
//    private ObservadorPropiedad observador;
    private GestorComandos gestorComandos;

    public GrupoPropiedades(String titulo) {
        this.titulo = titulo;
        listaPropiedades = new ArrayList<Propiedad>();
        diccionario = new Hashtable<String, Propiedad>();
        diccionarioAlias = new Hashtable<String, Propiedad>();

//        observadores = new ArrayList<ObservadorPropiedad>();
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        GrupoPropiedades clon = (GrupoPropiedades) super.clone();
        clon.listaPropiedades = new ArrayList<Propiedad>();
        clon.diccionario = new Hashtable<String, Propiedad>();
        clon.diccionarioAlias = new Hashtable<String, Propiedad>();
        
        for (Propiedad propiedad : listaPropiedades) {
            clon.agregarPropiedad((Propiedad) propiedad.clone());            
        }
        return clon;
    }

    public String getTitulo() {
        return titulo;
    }

    public void setTitulo(String titulo) {
        this.titulo = titulo;
    }

    public List<Propiedad> getLista() {
        return listaPropiedades;
    }
    
//    /**
//     * Prepara las propiedades para su uso. Se usa tras una deserialización.
//     */
//    public void preparar() {
//        diccionario.clear();
////        observadores.clear();
//        
//        for (Propiedad propiedad : listaPropiedades) {
//            prepararPropiedad(propiedad);
//        }
//    }
    public void asignarObjeto(Object objeto) {
        for (Propiedad propiedad : listaPropiedades) {
            propiedad.setObjeto(objeto);
//            propiedad.borrarObservadores();
            prepararPropiedad(propiedad);
        }
    }

    private void prepararPropiedad(Propiedad propiedad) {
        // Se anade la propiedad al diccionario
        diccionario.put(propiedad.getNombre(), propiedad);
        diccionarioAlias.put(propiedad.getAlias(), propiedad);
        propiedad.setGestorComandos(gestorComandos);

        // Se agrega el grupo como observador de la propiedad
//        propiedad.agregarObservador(this);
    }

//    public void agregarObservador(ObservadorPropiedad observador) {
////        System.out.println("Se añade al grupo el observador " + observador + " (" + observadores.size() + ")");
//        observadores.add(observador);
//    }
//
//    public void borrarObservador(ObservadorPropiedad observador) {
//        observadores.remove(observador);
//    }
//    public void borrarObservadores() {
////        System.out.println("Se borran los observadores del grupo");
//        observadores.clear();
//    }
//    /**
//     * Notifica a los observadores del grupo sobre el cambio de una propiedad del grupo.
//     * Metodo perteneciente a la interfaz ObservadorPropidad.
//     */
//    public void propiedadCambiada(Object objeto, Propiedad propiedad) {
//        for (ObservadorPropiedad observador : observadores) {
//            observador.propiedadCambiada(objeto, propiedad);
//        }
//    }

    public void agregarPropiedad(Propiedad propiedad) {
        if (propiedad != null) {
            listaPropiedades.add(propiedad);
            prepararPropiedad(propiedad);
        }
    }

    public int getNumeroPropiedades() {
        return listaPropiedades.size();
    }

    /**
     * Obtiene una propiedad.
     * @param nombre El nombre de la propiedad.
     */
    public Propiedad obtenerPropiedad(String nombre) {
        return diccionario.get(nombre);
    }

    /**
     * Obtiene una propiedad por el alias.
     * @param nombre El nombre de la propiedad.
     */
    public Propiedad obtenerPropiedadAlias(String alias) {
        return diccionarioAlias.get(alias);
    }

    /**
     * Obtiene una propiedad.
     * @param enumerado El enumerado que define a la propiedad.
     */
    public Propiedad obtenerPropiedad(Enum enumerado) {
        return obtenerPropiedad(enumerado.name());
    }

    /**
     * Obtiene una propiedad.
     * @param indice El indice (ordinal) de la propiedad.
     */
    public Propiedad obtenerPropiedad(int indice) {
        return listaPropiedades.get(indice);
    }

    public boolean parsearPropiedad(int indice, String valorString) {
        return listaPropiedades.get(indice).parsearPropiedad(valorString);
    }

    /**
     * Asigna el valor de una propiedad.
     */
    public void asignarValorPropiedad(String nombre, Object valor) {
        Propiedad propiedad = obtenerPropiedad(nombre);
        if (propiedad != null) {
            propiedad.setValor(valor);
        } else {
            System.err.println("El grupo no tiene la propiedad " + nombre);
        }
    }

    /**
     * Asigna el valor de una propiedad.
     */
    public void asignarValorPropiedad(Enum enumerado, Object valor) {
        asignarValorPropiedad(enumerado.name(), valor);
    }

    /**
     * Obtiene el valor de una propiedad.
     */
    public Object obtenerValorPropiedad(String nombre) {
        Propiedad propiedad = obtenerPropiedad(nombre);
//        if (propiedad == null) {
//            System.err.println("El grupo no tiene la propiedad " + nombre);
//        }
        return propiedad != null ? propiedad.getValor() : null;
    }

    /**
     * Obtiene el valor de una propiedad.
     */
    public Object obtenerValorPropiedad(Enum enumerado) {
        return obtenerValorPropiedad(enumerado.name());
    }

    /**
     * Obtiene una propiedad de texto.
     */
    public PropiedadTexto obtenerPropiedadTexto(Enum enumerado) {
        Propiedad propiedad = obtenerPropiedad(enumerado);
        if (propiedad != null && propiedad instanceof PropiedadTexto) {
            return (PropiedadTexto) propiedad;
        }
        return null;
    }

    public PropiedadNumericaReal obtenerPropiedadNumericaReal(Enum enumerado) {
        Propiedad propiedad = obtenerPropiedad(enumerado);
        if (propiedad != null && propiedad instanceof PropiedadNumericaReal) {
            return (PropiedadNumericaReal) propiedad;
        }
        return null;
    }

    /**
     * Obtiene propiedad de color indexada.
     */
    public PropiedadPintura obtenerPropiedadColor(Enum enumerado, int indice) {

        Propiedad propiedad = obtenerPropiedad(enumerado.name() + indice);
        if (propiedad != null && propiedad instanceof PropiedadPintura) {
            return (PropiedadPintura) propiedad;
        }
        return null;
    }

    /**
     * Obtiene una propiedad de fuente.
     */
    public PropiedadFuente obtenerPropiedadFuente(Enum enumerado) {
        Propiedad propiedad = obtenerPropiedad(enumerado);
        if (propiedad != null && propiedad instanceof PropiedadFuente) {
            return (PropiedadFuente) propiedad;
        }
        return null;
    }

    /**
     * Obtiene una propiedad de lista de numeros reales.
     */
    public PropiedadListaNumerosReales obtenerPropiedadListaNumerosReales(Enum enumerado) {
        Propiedad propiedad = obtenerPropiedad(enumerado);
        if (propiedad != null && propiedad instanceof PropiedadListaNumerosReales) {
            return (PropiedadListaNumerosReales) propiedad;
        }
        return null;
    }

    /**
     * Obtiene el valor booleano (boolean) de una propiedad.
     */
    public boolean obtenerValorPropiedadBooleana(Enum enumerado) {
        try {
            Object valor = obtenerValorPropiedad(enumerado);
            return valor != null ? (Boolean) valor : false;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    /**
     * Obtiene el valor entera (int) de una propiedad.
     */
    public double obtenerValorPropiedadEntera(Enum enumerado) {
        try {
            Object valor = obtenerValorPropiedad(enumerado);
            return valor != null ? (Integer) valor : 0;
        } catch (Exception ex) {
            ex.printStackTrace();
            return 0;
        }
    }

    /**
     * Obtiene el valor real (double) de una propiedad.
     */
    public double obtenerValorPropiedadReal(Enum enumerado) {
        try {
            Object valor = obtenerValorPropiedad(enumerado);
            return valor != null ? (Double) valor : 0;
        } catch (Exception ex) {
            ex.printStackTrace();
            return 0;
        }
    }

    /**
     * Obtiene el valor de texto (String) de una propiedad.
     */
    public String obtenerValorPropiedadTexto(Enum enumerado) {
        try {
            Object valor = obtenerValorPropiedad(enumerado);
            return valor != null ? (String) valor : "";
        } catch (Exception ex) {
            ex.printStackTrace();
            return "";
        }
    }

    /**
     * Obtiene el valor de colorde una propiedad.
     */
    public Color obtenerValorPropiedadColor(Enum enumerado) {
        try {
            Object valor = obtenerValorPropiedad(enumerado);
            return valor != null ? (Color) valor : Color.BLACK;
        } catch (Exception ex) {
            ex.printStackTrace();
            return Color.BLACK;
        }
    }

    /**
     * Obtiene el valor de color indexado de una propiedad.
     */
    public Color obtenerValorPropiedadColor(Enum enumerado, int indice) {
        try {
            Object valor = obtenerValorPropiedad(enumerado.name() + indice);
            return valor != null ? (Color) valor : Color.BLACK;
        } catch (Exception ex) {
            ex.printStackTrace();
            return Color.BLACK;
        }
    }

    /**
     * Obtiene el valor de fuente de una propiedad.
     */
    public Font obtenerValorPropiedadFuente(Enum enumerado) {
        try {
            Object valor = obtenerValorPropiedad(enumerado);
            return valor != null ? (Font) valor : null;
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }

    public void setGestorComandos(GestorComandos gestorComandos) {
        this.gestorComandos = gestorComandos;
        for (Propiedad propiedad : listaPropiedades) {
            propiedad.setGestorComandos(gestorComandos);
        }
    }
}
